#![no_std]
use core::ptr::{read_volatile, write_volatile};
use rkgpio;

const OFF_DATA: usize = 0x00; // port_dr
const OFF_DIR: usize = 0x08; // port_ddr
const OFF_INT_STATUS: usize = 0x50; // int_status (W1C)
const OFF_PORT_EOI: usize = 0x60; // port_eoi (W1C)
const OFF_EXT_PORT: usize = 0x70; // ext_port（输入采样）
const OFF_VERSION_ID: usize = 0x78; // version

#[inline]
fn rd32(base: *mut u8, off: usize) -> u32 {
    unsafe { read_volatile(base.add(off) as *const u32) }
}
#[inline]
fn wr32(base: *mut u8, off: usize, val: u32) {
    unsafe { write_volatile(base.add(off) as *mut u32, val) }
}

fn clear_irqs(base: *mut u8) {
    wr32(base, OFF_PORT_EOI, 0xffff_ffff);
    wr32(base, OFF_INT_STATUS, 0xffff_ffff);
}

fn dump_gpio_snapshot(tag: &str, base: *mut u8) {
    let ver = rd32(base, OFF_VERSION_ID);
    let dir = rd32(base, OFF_DIR);
    let dr = rd32(base, OFF_DATA);
    let ext = rd32(base, OFF_EXT_PORT);
    info!(
        "[{}] VER=0x{:08x}  DIR=0x{:08x}  DATA(latch)=0x{:08x}  EXT(in)=0x{:08x}",
        tag, ver, dir, dr, ext
    );
}

fn set_dir_bit_output(base: *mut u8, bit: u32, output: bool) {
    let mut dir = rd32(base, OFF_DIR);
    if output {
        dir |= 1 << bit;
    } else {
        dir &= !(1 << bit);
    }
    wr32(base, OFF_DIR, dir);
}

fn write_data_bit(base: *mut u8, bit: u32, high: bool) {
    let mut dr = rd32(base, OFF_DATA);
    if high {
        dr |= 1 << bit;
    } else {
        dr &= !(1 << bit);
    }
    wr32(base, OFF_DATA, dr);
}

fn read_pin_level(base: *mut u8, bit: u32) -> bool {
    ((rd32(base, OFF_EXT_PORT) >> bit) & 1) != 0
}

fn delay_cycles(mut n: u32) {
    while n > 0 {
        unsafe { core::arch::asm!("nop") };
        n -= 1;
    }
}

pub fn run_gpio() {
    // GPIO3 基地址与 IOMUX(IOC) 基地址，取自 DTS：
    //   gpio@fec40000 -> 0xFEC4_0000 (GPIO3)
    //   syscon@fd5f0000 (rk3588-ioc) -> 0xFD5F_0000
    const GPIO3_BASE: usize = 0xFEC4_0000;
    const IOC_BASE: usize = 0xFD5F_0000; // 注意：当前未映射，直接访问会触发 Data Abort

    // GPIO3 的全局 GPIO 号范围是 96..127（每组 32 个）
    // DTS 中 gpio-leds：blue gpios = <gpio3 6 0>, green gpios = <gpio3 9 0>
    let blue_pin_local: u8 = 6;   // 组内引脚号
    let green_pin_local: u8 = 9;
    let blue_global: u16 = 96 + blue_pin_local as u16;
    let green_global: u16 = 96 + green_pin_local as u16;

    // 持续闪烁 green_led（GPIO3_9），并保持 blue_led 熄灭
    // 注意：运行期需要使用平台的物理到虚拟地址转换
    let base_vaddr = axhal::mem::phys_to_virt((GPIO3_BASE as usize).into()).as_usize();
    let base = base_vaddr as *mut u8;
    let mut gpio = rkgpio::Gpio::new(base);
    gpio.gpio_init();

    // 设置为输出
    gpio.gpio_setdir(blue_pin_local, 1);
    gpio.gpio_setdir(green_pin_local, 1);

    // 先关蓝灯
    gpio.gpio_write(blue_pin_local, 0);

    info!(
        "Start blinking green LED on GPIO3_{} (global={})",
        green_pin_local, green_global
    );

    loop {
        gpio.gpio_write(green_pin_local, 1);
    }
}

pub fn probe_led_sequence(
    gpio_base: usize,
    pin: u8,
    iomux_base_opt: Option<usize>,
    global_gpio_num: u16,
) {
    let base = gpio_base as *mut u8;
    let bit = (pin % 32) as u32;
    info!(
        "=== GPIO LED probe begin: base=0x{:08x}, pin(local)={}, pin(global)={} ===",
        gpio_base, pin, global_gpio_num
    );

    // 配置 IOMUX 为 GPIO 功能（function=0）
    if let Some(ioc_base) = iomux_base_opt {
        let mut iomux = rkgpio::Iomux::new(ioc_base as *mut u8);
        iomux.set_iomux(global_gpio_num, 0);
    }

    // 使用 rkgpio 进行 v2 兼容的寄存器读写
    let mut gpio = rkgpio::Gpio::new(base);
    gpio.gpio_init();

    // 清中断并打印初始状态（低 16 位读取与 v2 兼容即可观测到 bit<16 的变化）
    clear_irqs(base);
    dump_gpio_snapshot("initial", base);
    info!(
        "initial pin level (EXT): {}",
        read_pin_level(base, bit) as u8
    );

    // 设置为输出并拉高/拉低
    gpio.gpio_setdir(pin, 1);
    delay_cycles(2000);
    dump_gpio_snapshot("dir->output", base);

    gpio.gpio_write(pin, 1);
    delay_cycles(50_000);
    dump_gpio_snapshot("write=HIGH", base);
    info!("pin level after HIGH: {}", read_pin_level(base, bit) as u8);

    gpio.gpio_write(pin, 0);
    delay_cycles(50_000);
    dump_gpio_snapshot("write=LOW", base);
    info!("pin level after LOW: {}", read_pin_level(base, bit) as u8);

    // 还原为输入
    gpio.gpio_setdir(pin, 0);
    delay_cycles(2000);
    dump_gpio_snapshot("dir->input", base);
    info!("=== GPIO LED probe end ===");
}
